<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Timeouts 💡</title>
<link rel="stylesheet" href="../../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../../index.html" title="Chapter 1. Boost.Beast">
<link rel="up" href="../using_io.html" title="Networking">
<link rel="prev" href="stream_types.html" title="Streams">
<link rel="next" href="rate_limiting.html" title="Rate Limiting 💡">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../../boost.png"></td>
<td align="center"><a href="../../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stream_types.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../using_io.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="rate_limiting.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="beast.using_io.timeouts"></a><a class="link" href="timeouts.html" title="Timeouts 💡">Timeouts 💡</a>
</h3></div></div></div>
<p>
        Network programs must handle adverse connection conditions; the most common
        is that a connected peer goes offline unexpectedly. Protocols have no way
        of identifying this reliably: the peer is offline after all, and unable to
        send a message announcing the absence. A peer can go offline for various
        reasons:
      </p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
            The peer experiences a power loss
          </li>
<li class="listitem">
            The peer becomes disconnected from the network
          </li>
<li class="listitem">
            The local host becomes disconnected from the network
          </li>
<li class="listitem">
            The network itself becomes unavailable
          </li>
</ul></div>
<p>
        To determine when a peer is offline or idle, a program will implement a
        <a href="https://en.wikipedia.org/wiki/Timeout_(computing)" target="_top">timeout</a>
        algorithm, which closes the connection after a specified amount of time if
        some condition is met. For example, if no data is received for the duration.
        A timeout may be used to:
      </p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
            Drop malicious or poorly performing hosts
          </li>
<li class="listitem">
            Close idle connections to free up resources
          </li>
<li class="listitem">
            Determine if a peer is offline or no longer available
          </li>
</ul></div>
<p>
        Traditionally, programs use a <a href="../../../../../../doc/html/boost_asio/reference/steady_timer.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">steady_timer</span></code></a>
        to determine when a timeout occurs, and then call <a href="../../../../../../doc/html/boost_asio/reference/basic_socket/close/overload2.html" target="_top"><code class="computeroutput"><span class="identifier">close</span></code></a> on the socket to release
        the resources. The complexity of managing a separate timer is often a source
        of <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1269r0.html#timers" target="_top">frustration</a>
        for non-experts.
      </p>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
          For portability reasons, networking does not provide timeouts or cancellation
          features for synchronous stream operations.
        </p></td></tr>
</table></div>
<p>
        To simplify the handling of timeouts, these provided types wrap a <a href="../../../../../../doc/html/boost_asio/reference/basic_stream_socket.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">basic_stream_socket</span></code></a>
        to provide additional features:
      </p>
<div class="informaltable"><table class="table">
<colgroup>
<col>
<col>
</colgroup>
<thead><tr>
<th>
                <p>
                  Name
                </p>
              </th>
<th>
                <p>
                  Features
                </p>
              </th>
</tr></thead>
<tbody>
<tr>
<td>
                <p>
                  <a class="link" href="../ref/boost__beast__tcp_stream.html" title="tcp_stream"><code class="computeroutput"><span class="identifier">tcp_stream</span></code></a>
                </p>
              </td>
<td>
                <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
                      Timeouts for logical operations
                    </li>
<li class="listitem">
                      <a href="../../../../../../doc/html/boost_asio/reference/ip__tcp.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span></code></a> protocol
                    </li>
<li class="listitem">
                      <a href="../../../../../../doc/html/boost_asio/reference/executor.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">executor</span></code></a> executor
                    </li>
<li class="listitem">
                      <a class="link" href="../ref/boost__beast__unlimited_rate_policy.html" title="unlimited_rate_policy"><code class="computeroutput"><span class="identifier">unlimited_rate_policy</span></code></a>
                      rate limits
                    </li>
</ul></div>
              </td>
</tr>
<tr>
<td>
                <p>
                  <a class="link" href="../ref/boost__beast__basic_stream.html" title="basic_stream"><code class="computeroutput"><span class="identifier">basic_stream</span></code></a>
                </p>
              </td>
<td>
                <div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
                      Timeouts for logical operations
                    </li>
<li class="listitem">
                      Configurable <a href="../../../../../../doc/html/boost_asio/reference/Protocol.html" target="_top"><span class="emphasis"><em>Protocol</em></span></a>
                      type
                    </li>
<li class="listitem">
                      Configurable <a href="../../../../../../doc/html/boost_asio/reference/Executor1.html" target="_top"><span class="emphasis"><em>Executor</em></span></a>
                      type
                    </li>
<li class="listitem">
                      Configurable <a class="link" href="../concepts/RatePolicy.html" title="RatePolicy"><span class="emphasis"><em>RatePolicy</em></span></a>
                      type
                    </li>
</ul></div>
              </td>
</tr>
</tbody>
</table></div>
<h5>
<a name="beast.using_io.timeouts.h0"></a>
        <span class="phrase"><a name="beast.using_io.timeouts.construction"></a></span><a class="link" href="timeouts.html#beast.using_io.timeouts.construction">Construction</a>
      </h5>
<p>
        The <code class="computeroutput"><span class="identifier">tcp_stream</span></code> is designed
        as a replacement for <a href="../../../../../../doc/html/boost_asio/reference/ip__tcp/socket.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span></code></a>. Any program which currently
        uses a socket, can switch to a <code class="computeroutput"><span class="identifier">tcp_stream</span></code>
        and achieve the features above (although some interfaces are different, see
        below). Networking now allows I/O objects to construct with any instance
        of <a href="../../../../../../doc/html/boost_asio/reference/ExecutionContext.html" target="_top"><span class="emphasis"><em>ExecutionContext</em></span></a>
        or <a href="../../../../../../doc/html/boost_asio/reference/Executor1.html" target="_top"><span class="emphasis"><em>Executor</em></span></a>
        objects. Here we construct a stream which uses a particular I/O context to
        dispatch completion handlers:
      </p>
<pre class="programlisting"><span class="comment">// `ioc` will be used to dispatch completion handlers</span>
<span class="identifier">tcp_stream</span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">);</span>
</pre>
<p>
        Alternatively, we can construct the stream from an executor:
      </p>
<pre class="programlisting"><span class="comment">// The resolver is used to look up the IP addresses for a domain name</span>
<span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">resolver</span> <span class="identifier">resolver</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">);</span>

<span class="comment">// The stream will use the same executor as the resolver</span>
<span class="identifier">tcp_stream</span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">resolver</span><span class="special">.</span><span class="identifier">get_executor</span><span class="special">());</span>
</pre>
<p>
        The function <a href="../../../../../../doc/html/boost_asio/reference/make_strand.html" target="_top"><code class="computeroutput"><span class="identifier">make_strand</span></code></a> returns a strand constructed
        from an execution context or executor. When a <a href="../../../../../../doc/html/boost_asio/reference/strand.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">strand</span></code></a>
        is chosen for the stream's executor, all completion handlers which do not
        already have an associated executor will use the strand. This is both a notational
        convenience (no need for <code class="computeroutput"><span class="identifier">strand</span><span class="special">::</span><span class="identifier">wrap</span></code>
        or <code class="computeroutput"><span class="identifier">bind_executor</span></code> at call
        sites) and a measure of safety, as it is no longer possible to forget to
        use the strand.
      </p>
<pre class="programlisting"><span class="comment">// The strand will be used to invoke all completion handlers</span>
<span class="identifier">tcp_stream</span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">make_strand</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">));</span>
</pre>
<h5>
<a name="beast.using_io.timeouts.h1"></a>
        <span class="phrase"><a name="beast.using_io.timeouts.connecting"></a></span><a class="link" href="timeouts.html#beast.using_io.timeouts.connecting">Connecting</a>
      </h5>
<p>
        Before data can be exchanged, the stream needs to be connected to a peer.
        The following code sets a timeout for an asynchronous connect operation.
        In Beast, functions to connect to a range of endpoints (such as the range
        returned by <a href="../../../../../../doc/html/boost_asio/reference/ip__basic_resolver/resolve/overload3.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">resolver</span><span class="special">::</span><span class="identifier">resolve</span></code></a>) are members of the class
        rather than free functions such as <a href="../../../../../../doc/html/boost_asio/reference/async_connect.html" target="_top"><code class="computeroutput"><span class="identifier">net</span><span class="special">::</span><span class="identifier">async_connect</span></code></a>.
      </p>
<pre class="programlisting"><span class="comment">// Set the logical operation timer to 30 seconds</span>
<span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_after</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">30</span><span class="special">));</span>

<span class="comment">// If the connection is not established within 30 seconds,</span>
<span class="comment">// the operation will be canceled and the handler will receive</span>
<span class="comment">// error::timeout as the error code.</span>

<span class="identifier">stream</span><span class="special">.</span><span class="identifier">async_connect</span><span class="special">(</span><span class="identifier">resolver</span><span class="special">.</span><span class="identifier">resolve</span><span class="special">(</span><span class="string">"www.example.com"</span><span class="special">,</span> <span class="string">"http"</span><span class="special">),</span>
    <span class="special">[](</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">endpoint</span> <span class="identifier">ep</span><span class="special">)</span>
    <span class="special">{</span>
        <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span> <span class="special">==</span> <span class="identifier">error</span><span class="special">::</span><span class="identifier">timeout</span><span class="special">)</span>
            <span class="identifier">std</span><span class="special">::</span><span class="identifier">cerr</span> <span class="special">&lt;&lt;</span> <span class="string">"async_connect took too long\n"</span><span class="special">;</span>
        <span class="keyword">else</span> <span class="keyword">if</span><span class="special">(!</span> <span class="identifier">ec</span><span class="special">)</span>
            <span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Connected to "</span> <span class="special">&lt;&lt;</span> <span class="identifier">ep</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
    <span class="special">}</span>
<span class="special">);</span>

<span class="comment">// The timer is still running. If we don't want the next</span>
<span class="comment">// operation to time out 30 seconds relative to the previous</span>
<span class="comment">// call  to `expires_after`, we need to turn it off before</span>
<span class="comment">// starting another asynchronous operation.</span>

<span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_never</span><span class="special">();</span>
</pre>
<p>
        A server will use an acceptor bound to a particular IP address and port to
        listen to and receive incoming connection requests. The acceptor returns
        an ordinary socket. A <code class="computeroutput"><span class="identifier">tcp_stream</span></code>
        can be move-constructed from the underlying <code class="computeroutput"><span class="identifier">basic_stream_socket</span></code>
        thusly:
      </p>
<pre class="programlisting"><span class="comment">// The acceptor is used to listen and accept incoming connections.</span>
<span class="comment">// We construct the acceptor to use a new strand, and listen</span>
<span class="comment">// on the loopback address with an operating-system assigned port.</span>

<span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">acceptor</span> <span class="identifier">acceptor</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">make_strand</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">));</span>
<span class="identifier">acceptor</span><span class="special">.</span><span class="identifier">bind</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">endpoint</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">make_address_v4</span><span class="special">(</span><span class="string">"127.0.0.1"</span><span class="special">),</span> <span class="number">0</span><span class="special">));</span>
<span class="identifier">acceptor</span><span class="special">.</span><span class="identifier">listen</span><span class="special">(</span><span class="number">0</span><span class="special">);</span>

<span class="comment">// This blocks until a new incoming connection is established.</span>
<span class="comment">// Upon success, the function returns a new socket which is</span>
<span class="comment">// connected to the peer. The socket will have its own executor,</span>
<span class="comment">// which in the call below is a new strand for the I/O context.</span>

<span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">socket</span> <span class="identifier">s</span> <span class="special">=</span> <span class="identifier">acceptor</span><span class="special">.</span><span class="identifier">accept</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">make_strand</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">));</span>

<span class="comment">// Construct a new tcp_stream from the connected socket.</span>
<span class="comment">// The stream will use the strand created when the connection</span>
<span class="comment">// was accepted.</span>

<span class="identifier">tcp_stream</span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">s</span><span class="special">));</span>
</pre>
<h5>
<a name="beast.using_io.timeouts.h2"></a>
        <span class="phrase"><a name="beast.using_io.timeouts.reading_and_writing"></a></span><a class="link" href="timeouts.html#beast.using_io.timeouts.reading_and_writing">Reading
        and Writing</a>
      </h5>
<p>
        Timeouts apply to the logical operation, expressed as a series of asynchronous
        calls, rather than just the next call. This code reads a line from the stream
        and writes it back. Both the read and the write must complete within 30 seconds
        from when the timeout was set; the timer is not reset between operations.
      </p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s</span><span class="special">;</span>

<span class="comment">// Set the logical operation timer to 30 seconds.</span>
<span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_after</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">30</span><span class="special">));</span>

<span class="comment">// Read a line from the stream into the string.</span>
<span class="identifier">net</span><span class="special">::</span><span class="identifier">async_read_until</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">dynamic_buffer</span><span class="special">(</span><span class="identifier">s</span><span class="special">),</span> <span class="char">'\n'</span><span class="special">,</span>
    <span class="special">[&amp;</span><span class="identifier">s</span><span class="special">,</span> <span class="special">&amp;</span><span class="identifier">stream</span><span class="special">](</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">bytes_transferred</span><span class="special">)</span>
    <span class="special">{</span>
        <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
            <span class="keyword">return</span><span class="special">;</span>

        <span class="comment">// read_until can read past the '\n', these will end up in</span>
        <span class="comment">// our buffer but we don't want to echo those extra received</span>
        <span class="comment">// bytes. `bytes_transferred` will be the number of bytes</span>
        <span class="comment">// up to and including the '\n'. We use `buffers_prefix` so</span>
        <span class="comment">// that extra data is not written.</span>

        <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">buffers_prefix</span><span class="special">(</span><span class="identifier">bytes_transferred</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">s</span><span class="special">)),</span>
            <span class="special">[&amp;</span><span class="identifier">s</span><span class="special">](</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">bytes_transferred</span><span class="special">)</span>
            <span class="special">{</span>
                <span class="comment">// Consume the line from the buffer</span>
                <span class="identifier">s</span><span class="special">.</span><span class="identifier">erase</span><span class="special">(</span><span class="identifier">s</span><span class="special">.</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">s</span><span class="special">.</span><span class="identifier">begin</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">bytes_transferred</span><span class="special">);</span>

                <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
                    <span class="identifier">std</span><span class="special">::</span><span class="identifier">cerr</span> <span class="special">&lt;&lt;</span> <span class="string">"Error: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">ec</span><span class="special">.</span><span class="identifier">message</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
            <span class="special">});</span>
    <span class="special">});</span>
</pre>
<p>
        Since reads and writes can take place concurrently, it is possible to have
        two simultaneous logical operations where each operation either only reads,
        or only writes. The beginning of a new read or write operation will use the
        most recently set timeout. This will not affect operations that are already
        outstanding.
      </p>
<pre class="programlisting"><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s1</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">s2</span><span class="special">;</span>

<span class="comment">// Set the logical operation timer to 15 seconds.</span>
<span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_after</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">15</span><span class="special">));</span>

<span class="comment">// Read another line from the stream into our dynamic buffer.</span>
<span class="comment">// The operation will time out after 15 seconds.</span>

<span class="identifier">net</span><span class="special">::</span><span class="identifier">async_read_until</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">dynamic_buffer</span><span class="special">(</span><span class="identifier">s1</span><span class="special">),</span> <span class="char">'\n'</span><span class="special">,</span> <span class="identifier">handler</span><span class="special">);</span>

<span class="comment">// Set the logical operation timer to 30 seconds.</span>
<span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_after</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">30</span><span class="special">));</span>

<span class="comment">// Write the contents of the other buffer.</span>
<span class="comment">// This operation will time out after 30 seconds.</span>

<span class="identifier">net</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(</span><span class="identifier">s2</span><span class="special">),</span> <span class="identifier">handler</span><span class="special">);</span>
</pre>
<p>
        When a timeout is set, it cancels any previous read or write timeout for
        which no outstanding operation is in progress. Algorithms which loop over
        logical operations simply need to set the timeout once before the logical
        operation, it is not necessary to call <code class="computeroutput"><span class="identifier">expires_never</span></code>
        in this case. Here we implement an algorithm which continuously echoes lines
        back, with a timeout. This example is implemented as a complete function.
      </p>
<pre class="programlisting"><span class="comment">/** This function echoes back received lines from a peer, with a timeout.

    The algorithm terminates upon any error (including timeout).
*/</span>
<span class="keyword">template</span> <span class="special">&lt;</span><span class="keyword">class</span> <span class="identifier">Protocol</span><span class="special">,</span> <span class="keyword">class</span> <span class="identifier">Executor</span><span class="special">&gt;</span>
<span class="keyword">void</span> <span class="identifier">do_async_echo</span> <span class="special">(</span><span class="identifier">basic_stream</span><span class="special">&lt;</span><span class="identifier">Protocol</span><span class="special">,</span> <span class="identifier">Executor</span><span class="special">&gt;&amp;</span> <span class="identifier">stream</span><span class="special">)</span>
<span class="special">{</span>
    <span class="comment">// This object will hold our state when reading the line.</span>

    <span class="keyword">struct</span> <span class="identifier">echo_line</span>
    <span class="special">{</span>
        <span class="identifier">basic_stream</span><span class="special">&lt;</span><span class="identifier">Protocol</span><span class="special">,</span> <span class="identifier">Executor</span><span class="special">&gt;&amp;</span> <span class="identifier">stream</span><span class="special">;</span>

        <span class="comment">// The shared pointer is used to extend the lifetime of the</span>
        <span class="comment">// string until the last asynchronous operation completes.</span>
        <span class="identifier">std</span><span class="special">::</span><span class="identifier">shared_ptr</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;</span> <span class="identifier">s</span><span class="special">;</span>

        <span class="comment">// This starts a new operation to read and echo a line</span>
        <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()()</span>
        <span class="special">{</span>
            <span class="comment">// If a line is not sent and received within 30 seconds, then</span>
            <span class="comment">// the connection will be closed and this algorithm will terminate.</span>

            <span class="identifier">stream</span><span class="special">.</span><span class="identifier">expires_after</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">30</span><span class="special">));</span>

            <span class="comment">// Read a line from the stream into our dynamic buffer, with a timeout</span>
            <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_read_until</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">dynamic_buffer</span><span class="special">(*</span><span class="identifier">s</span><span class="special">),</span> <span class="char">'\n'</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(*</span><span class="keyword">this</span><span class="special">));</span>
        <span class="special">}</span>

        <span class="comment">// This function is called when the read completes</span>
        <span class="keyword">void</span> <span class="keyword">operator</span><span class="special">()(</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">bytes_transferred</span><span class="special">)</span>
        <span class="special">{</span>
            <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
                <span class="keyword">return</span><span class="special">;</span>

            <span class="identifier">net</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">buffers_prefix</span><span class="special">(</span><span class="identifier">bytes_transferred</span><span class="special">,</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">buffer</span><span class="special">(*</span><span class="identifier">s</span><span class="special">)),</span>
                <span class="special">[</span><span class="keyword">this</span><span class="special">](</span><span class="identifier">error_code</span> <span class="identifier">ec</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">size_t</span> <span class="identifier">bytes_transferred</span><span class="special">)</span>
                <span class="special">{</span>
                    <span class="identifier">s</span><span class="special">-&gt;</span><span class="identifier">erase</span><span class="special">(</span><span class="identifier">s</span><span class="special">-&gt;</span><span class="identifier">begin</span><span class="special">(),</span> <span class="identifier">s</span><span class="special">-&gt;</span><span class="identifier">begin</span><span class="special">()</span> <span class="special">+</span> <span class="identifier">bytes_transferred</span><span class="special">);</span>

                    <span class="keyword">if</span><span class="special">(!</span> <span class="identifier">ec</span><span class="special">)</span>
                    <span class="special">{</span>
                        <span class="comment">// Run this algorithm again</span>
                        <span class="identifier">echo_line</span><span class="special">{</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">s</span><span class="special">)}();</span>
                    <span class="special">}</span>
                    <span class="keyword">else</span>
                    <span class="special">{</span>
                        <span class="identifier">std</span><span class="special">::</span><span class="identifier">cerr</span> <span class="special">&lt;&lt;</span> <span class="string">"Error: "</span> <span class="special">&lt;&lt;</span> <span class="identifier">ec</span><span class="special">.</span><span class="identifier">message</span><span class="special">()</span> <span class="special">&lt;&lt;</span> <span class="string">"\n"</span><span class="special">;</span>
                    <span class="special">}</span>
                <span class="special">});</span>
        <span class="special">}</span>
    <span class="special">};</span>

    <span class="comment">// Create the operation and run it</span>
    <span class="identifier">echo_line</span><span class="special">{</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">make_shared</span><span class="special">&lt;</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span><span class="special">&gt;()}();</span>
<span class="special">}</span>
</pre>
<h5>
<a name="beast.using_io.timeouts.h3"></a>
        <span class="phrase"><a name="beast.using_io.timeouts.https_get"></a></span><a class="link" href="timeouts.html#beast.using_io.timeouts.https_get">https_get</a>
      </h5>
<p>
        It is important to note that all of the examples thus far which perform reads
        and writes with a timeout, make use of the existing networking stream algorithms.
        As these algorithms are written generically to work with any object meeting
        the stream requirements, they transparently support timeouts when used with
        <code class="computeroutput"><span class="identifier">tcp_stream</span></code>. This can be used
        to enable timeouts for stream wrappers that do not currently support timeouts.
      </p>
<p>
        The following code establishes an encrypted connection, writes an HTTP request,
        reads the HTTP response, and closes the connection gracefully. If these operations
        take longer than 30 seconds total, a timeout occurs. This code is intended
        to show how <code class="computeroutput"><span class="identifier">tcp_stream</span></code> can
        be used to enable timeouts across unmodified stream algorithms which were
        not originally written to support timing out, and how a blocking algorithm
        may be written from asynchronous intermediate operations.
      </p>
<pre class="programlisting"><span class="comment">/** Request an HTTP resource from a TLS host and return it as a string, with a timeout.

    This example uses fibers (stackful coroutines) and its own I/O context.
*/</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span>
<span class="identifier">https_get</span> <span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">host</span><span class="special">,</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="keyword">const</span><span class="special">&amp;</span> <span class="identifier">target</span><span class="special">,</span> <span class="identifier">error_code</span><span class="special">&amp;</span> <span class="identifier">ec</span><span class="special">)</span>
<span class="special">{</span>
    <span class="comment">// It is the responsibility of the algorithm to clear the error first.</span>
    <span class="identifier">ec</span> <span class="special">=</span> <span class="special">{};</span>

    <span class="comment">// We use our own I/O context, to make this function blocking.</span>
    <span class="identifier">net</span><span class="special">::</span><span class="identifier">io_context</span> <span class="identifier">ioc</span><span class="special">;</span>

    <span class="comment">// This context is used to hold client and server certificates.</span>
    <span class="comment">// We do not perform certificate verification in this example.</span>

    <span class="identifier">net</span><span class="special">::</span><span class="identifier">ssl</span><span class="special">::</span><span class="identifier">context</span> <span class="identifier">ctx</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">ssl</span><span class="special">::</span><span class="identifier">context</span><span class="special">::</span><span class="identifier">tlsv12</span><span class="special">);</span>

    <span class="comment">// This string will hold the body of the HTTP response, if any.</span>
    <span class="identifier">std</span><span class="special">::</span><span class="identifier">string</span> <span class="identifier">result</span><span class="special">;</span>

    <span class="comment">// Note that Networking TS does not come with spawn. This function</span>
    <span class="comment">// launches a "fiber" which is a coroutine that has its own separately</span>
    <span class="comment">// allocated stack.</span>

    <span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">spawn</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">,</span>
    <span class="special">[&amp;](</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">asio</span><span class="special">::</span><span class="identifier">yield_context</span> <span class="identifier">yield</span><span class="special">)</span>
    <span class="special">{</span>
        <span class="comment">// We use the Beast ssl_stream wrapped around a beast tcp_stream.</span>
        <span class="identifier">ssl_stream</span><span class="special">&lt;</span><span class="identifier">tcp_stream</span><span class="special">&gt;</span> <span class="identifier">stream</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">,</span> <span class="identifier">ctx</span><span class="special">);</span>

        <span class="comment">// The resolver will be used to look up the IP addresses for the host name</span>
        <span class="identifier">net</span><span class="special">::</span><span class="identifier">ip</span><span class="special">::</span><span class="identifier">tcp</span><span class="special">::</span><span class="identifier">resolver</span> <span class="identifier">resolver</span><span class="special">(</span><span class="identifier">ioc</span><span class="special">);</span>

        <span class="comment">// First, look up the name. Networking has its own timeout for this.</span>
        <span class="comment">// The `yield` object is a CompletionToken which specializes the</span>
        <span class="comment">// `net::async_result` customization point to make the fiber work.</span>
        <span class="comment">//</span>
        <span class="comment">// This call will appear to "block" until the operation completes.</span>
        <span class="comment">// It isn't really blocking. Instead, the fiber implementation saves</span>
        <span class="comment">// the call stack and suspends the function until the asynchronous</span>
        <span class="comment">// operation is complete. Then it restores the call stack, and resumes</span>
        <span class="comment">// the function to the statement following the async_resolve. This</span>
        <span class="comment">// allows an asynchronous algorithm to be expressed synchronously.</span>

        <span class="keyword">auto</span> <span class="keyword">const</span> <span class="identifier">endpoints</span> <span class="special">=</span> <span class="identifier">resolver</span><span class="special">.</span><span class="identifier">async_resolve</span><span class="special">(</span><span class="identifier">host</span><span class="special">,</span> <span class="string">"https"</span><span class="special">,</span> <span class="special">{},</span> <span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span>
        <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
            <span class="keyword">return</span><span class="special">;</span>

        <span class="comment">// The function `get_lowest_layer` retrieves the "bottom most" object</span>
        <span class="comment">// in the stack of stream layers. In this case it will be the tcp_stream.</span>
        <span class="comment">// This timeout will apply to all subsequent operations collectively.</span>
        <span class="comment">// That is to say, they must all complete within the same 30 second</span>
        <span class="comment">// window.</span>

        <span class="identifier">get_lowest_layer</span><span class="special">(</span><span class="identifier">stream</span><span class="special">).</span><span class="identifier">expires_after</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">chrono</span><span class="special">::</span><span class="identifier">seconds</span><span class="special">(</span><span class="number">30</span><span class="special">));</span>

        <span class="comment">// `tcp_stream` range connect algorithms are member functions, unlike net::</span>
        <span class="identifier">get_lowest_layer</span><span class="special">(</span><span class="identifier">stream</span><span class="special">).</span><span class="identifier">async_connect</span><span class="special">(</span><span class="identifier">endpoints</span><span class="special">,</span> <span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span>
        <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
            <span class="keyword">return</span><span class="special">;</span>

        <span class="comment">// Perform the TLS handshake</span>
        <span class="identifier">stream</span><span class="special">.</span><span class="identifier">async_handshake</span><span class="special">(</span><span class="identifier">net</span><span class="special">::</span><span class="identifier">ssl</span><span class="special">::</span><span class="identifier">stream_base</span><span class="special">::</span><span class="identifier">client</span><span class="special">,</span> <span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span>
        <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
            <span class="keyword">return</span><span class="special">;</span>

        <span class="comment">// Send an HTTP GET request for the target</span>
        <span class="special">{</span>
            <span class="identifier">http</span><span class="special">::</span><span class="identifier">request</span><span class="special">&lt;</span><span class="identifier">http</span><span class="special">::</span><span class="identifier">empty_body</span><span class="special">&gt;</span> <span class="identifier">req</span><span class="special">;</span>
            <span class="identifier">req</span><span class="special">.</span><span class="identifier">method</span><span class="special">(</span><span class="identifier">http</span><span class="special">::</span><span class="identifier">verb</span><span class="special">::</span><span class="identifier">get</span><span class="special">);</span>
            <span class="identifier">req</span><span class="special">.</span><span class="identifier">target</span><span class="special">(</span><span class="identifier">target</span><span class="special">);</span>
            <span class="identifier">req</span><span class="special">.</span><span class="identifier">version</span><span class="special">(</span><span class="number">11</span><span class="special">);</span>
            <span class="identifier">req</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">http</span><span class="special">::</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">host</span><span class="special">,</span> <span class="identifier">host</span><span class="special">);</span>
            <span class="identifier">req</span><span class="special">.</span><span class="identifier">set</span><span class="special">(</span><span class="identifier">http</span><span class="special">::</span><span class="identifier">field</span><span class="special">::</span><span class="identifier">user_agent</span><span class="special">,</span> <span class="string">"Beast"</span><span class="special">);</span>
            <span class="identifier">http</span><span class="special">::</span><span class="identifier">async_write</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">req</span><span class="special">,</span> <span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span>
            <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
                <span class="keyword">return</span><span class="special">;</span>
        <span class="special">}</span>

        <span class="comment">// Now read the response</span>
        <span class="identifier">flat_buffer</span> <span class="identifier">buffer</span><span class="special">;</span>
        <span class="identifier">http</span><span class="special">::</span><span class="identifier">response</span><span class="special">&lt;</span><span class="identifier">http</span><span class="special">::</span><span class="identifier">string_body</span><span class="special">&gt;</span> <span class="identifier">res</span><span class="special">;</span>
        <span class="identifier">http</span><span class="special">::</span><span class="identifier">async_read</span><span class="special">(</span><span class="identifier">stream</span><span class="special">,</span> <span class="identifier">buffer</span><span class="special">,</span> <span class="identifier">res</span><span class="special">,</span> <span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span>
        <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
            <span class="keyword">return</span><span class="special">;</span>

        <span class="comment">// Try to perform the TLS shutdown handshake</span>
        <span class="identifier">stream</span><span class="special">.</span><span class="identifier">async_shutdown</span><span class="special">(</span><span class="identifier">yield</span><span class="special">[</span><span class="identifier">ec</span><span class="special">]);</span>

        <span class="comment">// `net::ssl::error::stream_truncated`, also known as an SSL "short read",</span>
        <span class="comment">// indicates the peer closed the connection without performing the</span>
        <span class="comment">// required closing handshake (for example, Google does this to</span>
        <span class="comment">// improve performance). Generally this can be a security issue,</span>
        <span class="comment">// but if your communication protocol is self-terminated (as</span>
        <span class="comment">// it is with both HTTP and WebSocket) then you may simply</span>
        <span class="comment">// ignore the lack of close_notify:</span>
        <span class="comment">//</span>
        <span class="comment">// https://github.com/boostorg/beast/issues/38</span>
        <span class="comment">//</span>
        <span class="comment">// https://security.stackexchange.com/questions/91435/how-to-handle-a-malicious-ssl-tls-shutdown</span>
        <span class="comment">//</span>
        <span class="comment">// When a short read would cut off the end of an HTTP message,</span>
        <span class="comment">// Beast returns the error beast::http::error::partial_message.</span>
        <span class="comment">// Therefore, if we see a short read here, it has occurred</span>
        <span class="comment">// after the message has been completed, so it is safe to ignore it.</span>

        <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span> <span class="special">==</span> <span class="identifier">net</span><span class="special">::</span><span class="identifier">ssl</span><span class="special">::</span><span class="identifier">error</span><span class="special">::</span><span class="identifier">stream_truncated</span><span class="special">)</span>
            <span class="identifier">ec</span> <span class="special">=</span> <span class="special">{};</span>
        <span class="keyword">else</span> <span class="keyword">if</span><span class="special">(</span><span class="identifier">ec</span><span class="special">)</span>
            <span class="keyword">return</span><span class="special">;</span>

        <span class="comment">// Set the string to return to the caller</span>
        <span class="identifier">result</span> <span class="special">=</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">move</span><span class="special">(</span><span class="identifier">res</span><span class="special">.</span><span class="identifier">body</span><span class="special">());</span>
    <span class="special">});</span>

    <span class="comment">// `run` will dispatch completion handlers, and block until there is</span>
    <span class="comment">// no more "work" remaining. When this call returns, the operations</span>
    <span class="comment">// are complete and we can give the caller the result.</span>
    <span class="identifier">ioc</span><span class="special">.</span><span class="identifier">run</span><span class="special">();</span>

    <span class="keyword">return</span> <span class="identifier">result</span><span class="special">;</span>
<span class="special">}</span>
</pre>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright © 2016-2019 Vinnie
      Falco<p>
        Distributed under the Boost Software License, Version 1.0. (See accompanying
        file LICENSE_1_0.txt or copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>)
      </p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="stream_types.html"><img src="../../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../using_io.html"><img src="../../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../../index.html"><img src="../../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="rate_limiting.html"><img src="../../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>
